<script type="text/x-red" data-template-name="api-credentials">
    <div class="form-row">
        <label><i class="icon-bookmark"></i> Username</label>
        <input type="text" id="node-config-input-username">
    </div>
    <div class="form-row">
        <label><i class="icon-bookmark"></i> Password</label>
        <input type="password" id="node-config-input-password">
    </div>
</script>
<script type="text/javascript">
    RED.nodes.registerType('api-credentials',{
        category: 'config',
        defaults: {
        },
        credentials: {
            username: { type:"text" },
            password: { type: "password" }
        },
        label: function() {
            return this.name || "api credentials";
        }
    });
</script>


<script type="text/x-red" data-template-name="api get jwt">
    <!-- readonly onfocus="this.removeAttribute('readonly');" autocomplete="off" -->
    <div class="form-row">
        <label for="node-input-config"><i class="fa fa-globe"></i> Config</label>
        <input type="text" id="node-input-config">
    </div>
    <div class="form-row">
        <label ><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Node name">
    </div>
</script>
<script type="text/x-red" data-help-name="api get jwt">
Request a JWT token for talking with API. Leave config blank to impersonate root.
</script>
<script type="text/javascript">
    RED.nodes.registerType('api get jwt', {
        category: 'api',
        color: "#a6bbcf",
        defaults: {
            name: { value: "" },
            config: {value:"",type:"api-credentials", required:false}
        },
        inputs: 1,
        outputs: 1,
        icon: "bridge.png",
        label: function () {
            return this.name || "api get jwt";
        },
        labelStyle: function () {
            return this.name ? "node_label_italic" : "";
        },

    });
</script>







<script type="text/x-red" data-template-name="api get">
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Query</label>
        <input type="text" id="node-input-query" placeholder="Mongo Query">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Projection</label>
        <input type="text" id="node-input-projection" placeholder="Projection">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Collection</label>
        <input type="text" id="node-input-collection" placeholder="Collection">
    </div>
    <div class="form-row">
        <label><i class="fa fa-list"></i> Result to</label>
        <input id="node-input-typed-resultfield" type="text" style="width: 70%">
        <input id="node-input-resultfield" type="hidden">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Orderby</label>
        <input type="text" id="node-input-orderby" placeholder="Order result by this property">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Top</label>
        <input type="text" id="node-input-top" placeholder="Limit number of results">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Skip</label>
        <input type="text" id="node-input-skip" placeholder="Skip a number of results">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
</script>
<script type="text/x-red" data-help-name="api get">
    <p>Get items from a collection, based on a Mongo <a href="https://docs.mongodb.com/manual/reference/method/db.collection.find/" target="_blank">query</a></p>
</script>
<script type="text/javascript">
    RED.nodes.registerType('api get', {
        category: 'api',
        color: "#a6bbcf",
        defaults: {
            name: { value: "" },
            query: { value: "" },
            projection: { value: "" },
            orderby: { value: "" },
            top: { value: 500, required: true },
            skip: { value: 0 },
            collection: { value: "entities", required: true },
            resultfield: { value: "payload", required: true },
        },
        inputs: 1,
        outputs: 1,
        icon: "bridge.png",
        label: function () {
            return this.name || "api get";
        },
        labelStyle: function () {
            return this.name ? "node_label_italic" : "";
        },
        oneditprepare: function () {
            $("#node-input-typed-resultfield").typedInput(
                { types: ['msg'] }
            );
            $("#node-input-typed-resultfield").typedInput('value', this.resultfield);
        },
        oneditsave: function () {
            $("#node-input-resultfield").val($("#node-input-typed-resultfield").typedInput('value'));
        }

    });

</script>





<script type="text/x-red" data-template-name="api add">
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Type</label>
        <input type="text" id="node-input-entitytype" placeholder="Override new entity type">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Collection</label>
        <input type="text" id="node-input-collection" placeholder="Collection">
    </div>
    <div class="form-row">
        <label><i class="fa fa-list"></i> Entity from</label>
        <input id="node-input-typed-inputfield" type="text" style="width: 70%">
        <input id="node-input-inputfield" type="hidden">
    </div>
    <div class="form-row">
        <label><i class="fa fa-list"></i> Result to</label>
        <input id="node-input-typed-resultfield" type="text" style="width: 70%">
        <input id="node-input-resultfield" type="hidden">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
</script>
<script type="text/x-red" data-help-name="api add">
    <p>Add payload as new entity in collection, can be an object or array of objects, returns an array of results</p>
</script>
<script type="text/javascript">
    RED.nodes.registerType('api add', {
        category: 'api',
        color: "#a6bbcf",
        defaults: {
            name: { value: "" },
            entitytype: { value: "" },
            collection: { value: "entities", required: true },
            inputfield: { value: "payload", required: true },
            resultfield: { value: "payload", required: true }
        },
        inputs: 1,
        outputs: 1,
        icon: "bridge.png",
        label: function () {
            return this.name || "api add";
        },
        labelStyle: function () {
            return this.name ? "node_label_italic" : "";
        },

        oneditprepare: function () {
            $("#node-input-typed-inputfield").typedInput({ types: ['msg'] });
            $("#node-input-typed-inputfield").typedInput('value', this.inputfield);
            $("#node-input-typed-resultfield").typedInput({ types: ['msg'] });
            $("#node-input-typed-resultfield").typedInput('value', this.resultfield);
        },
        oneditsave: function () {
            $("#node-input-inputfield").val($("#node-input-typed-inputfield").typedInput('value'));
            $("#node-input-resultfield").val($("#node-input-typed-resultfield").typedInput('value'));
        }

    });

</script>


<script type="text/x-red" data-template-name="api update">
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Type</label>
        <input type="text" id="node-input-entitytype" placeholder="Override new entity type">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Collection</label>
        <input type="text" id="node-input-collection" placeholder="Collection">
    </div>
    <div class="form-row">
        <label><i class="fa fa-list"></i> Entity from</label>
        <input id="node-input-typed-inputfield" type="text" style="width: 70%">
        <input id="node-input-inputfield" type="hidden">
    </div>
    <div class="form-row">
        <label><i class="fa fa-list"></i> Result to</label>
        <input id="node-input-typed-resultfield" type="text" style="width: 70%">
        <input id="node-input-resultfield" type="hidden">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
</script>
<script type="text/x-red" data-help-name="api update">
    <p>Update payload in database, payload can be an object or array of objects, returns an array of results</p>
</script>
<script type="text/javascript">
    RED.nodes.registerType('api update', {
        category: 'api',
        color: "#a6bbcf",
        defaults: {
            name: { value: "" },
            entitytype: { value: "" },
            collection: { value: "entities", required: true },
            inputfield: { value: "payload", required: true },
            resultfield: { value: "payload", required: true }
        },
        inputs: 1,
        outputs: 1,
        icon: "bridge.png",
        label: function () {
            return this.name || "api update";
        },
        labelStyle: function () {
            return this.name ? "node_label_italic" : "";
        },

        oneditprepare: function () {
            $("#node-input-typed-inputfield").typedInput({ types: ['msg'] });
            $("#node-input-typed-inputfield").typedInput('value', this.inputfield);
            $("#node-input-typed-resultfield").typedInput({ types: ['msg'] });
            $("#node-input-typed-resultfield").typedInput('value', this.resultfield);
        },
        oneditsave: function () {
            $("#node-input-inputfield").val($("#node-input-typed-inputfield").typedInput('value'));
            $("#node-input-resultfield").val($("#node-input-typed-resultfield").typedInput('value'));
        }

    });

</script>



<script type="text/x-red" data-template-name="api addorupdate">
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Type</label>
        <input type="text" id="node-input-entitytype" placeholder="Override new entity type">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Collection</label>
        <input type="text" id="node-input-collection" placeholder="Collection">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Uniqeness</label>
        <input type="text" id="node-input-uniqeness" placeholder="Comma list of fields to compare by">
    </div>
    <div class="form-row">
        <label><i class="fa fa-list"></i> Entity from</label>
        <input id="node-input-typed-inputfield" type="text" style="width: 70%">
        <input id="node-input-inputfield" type="hidden">
    </div>
    <div class="form-row">
        <label><i class="fa fa-list"></i> Result to</label>
        <input id="node-input-typed-resultfield" type="text" style="width: 70%">
        <input id="node-input-resultfield" type="hidden">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
</script>
<script type="text/x-red" data-help-name="api addorupdate">
    <p>
        Add or Update an item og array of items in data.<br />
        Checks for uniqeness based on _id. If uniqeness should be checked agains other fields, supply them in the uniqeness field.
        To check on more than one field, seperate fields with comma.<br>
        Returns an array of results
    </p>
</script>
<script type="text/javascript">
    RED.nodes.registerType('api addorupdate', {
        category: 'api',
        color: "#a6bbcf",
        defaults: {
            name: { value: "" },
            entitytype: { value: "" },
            collection: { value: "entities", required: true },
            inputfield: { value: "payload", required: true },
            resultfield: { value: "payload", required: true },
            uniqeness: { value: "", required: false }
        },
        inputs: 1,
        outputs: 1,
        icon: "bridge.png",
        label: function () {
            return this.name || "api addorupdate";
        },
        labelStyle: function () {
            return this.name ? "node_label_italic" : "";
        },

        oneditprepare: function () {
            $("#node-input-typed-inputfield").typedInput({ types: ['msg'] });
            $("#node-input-typed-inputfield").typedInput('value', this.inputfield);
            $("#node-input-typed-resultfield").typedInput({ types: ['msg'] });
            $("#node-input-typed-resultfield").typedInput('value', this.resultfield);
        },
        oneditsave: function () {
            $("#node-input-inputfield").val($("#node-input-typed-inputfield").typedInput('value'));
            $("#node-input-resultfield").val($("#node-input-typed-resultfield").typedInput('value'));
        }

    });

</script>





<script type="text/x-red" data-template-name="api delete">
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Collection</label>
        <input type="text" id="node-input-collection" placeholder="Collection">
    </div>
    <div class="form-row">
        <label><i class="fa fa-list"></i> Entity from</label>
        <input id="node-input-typed-inputfield" type="text" style="width: 70%">
        <input id="node-input-inputfield" type="hidden">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
</script>
<script type="text/x-red" data-help-name="api delete">
    <p>Deletes payload from database. Payload can be a string with the id, or an object with an _id field, or an array of text/objects</p>
</script>
<script type="text/javascript">
    RED.nodes.registerType('api delete', {
        category: 'api',
        color: "#a6bbcf",
        defaults: {
            name: { value: "" },
            entitytype: { value: "" },
            collection: { value: "entities", required: true },
            inputfield: { value: "payload", required: true }
        },
        inputs: 1,
        outputs: 1,
        icon: "bridge.png",
        label: function () {
            return this.name || "api delete";
        },
        labelStyle: function () {
            return this.name ? "node_label_italic" : "";
        },

        oneditprepare: function () {
            $("#node-input-typed-inputfield").typedInput({ types: ['msg'] });
            $("#node-input-typed-inputfield").typedInput('value', this.inputfield);
        },
        oneditsave: function () {
            $("#node-input-inputfield").val($("#node-input-typed-inputfield").typedInput('value'));
        }

    });
</script>






<script type="text/x-red" data-template-name="grant permission">
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
    <div class="form-row">
        <label for="node-input-targetid"><i class="fa fa-tasks"></i> Target</label>
        <select id="node-input-targetid-select">
        </select>
        <input id="node-input-targetid" type="hidden">
    </div>
    <div class="form-row">
        <label for="node-input-typed-entities"><i class="fa fa-list"></i> Entities</label>
        <input id="node-input-typed-entities" type="text" style="width: 70%">
        <input id="node-input-entities" type="hidden">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Bitsexplained </label>
        (F:-1, R:2, U:3, D:4, I:5)
    </div>
    <div class="form-row">
        <label for="node-input-bits"><i class="fa fa-tag"></i> Bits </label>
        <input type="text" id="node-input-bits" placeholder="Bits seperated by comma,">
    </div>
</script>
<script type="text/x-red" data-help-name="grant permission">
    <p>Grants a role (or user if set by msg.targetid) a specific permission on the entity/entities in payload.</p>
</script>
<script type="text/javascript">
    RED.nodes.registerType('grant permission', {
        category: 'api',
        color: "#a6bbcf",
        defaults: {
            name: { value: "" },
            targetid: { value: "result._id", required: true },
            entities: { value: "payload", required: true },
            bits: { value: "", required: true }
        },
        inputs: 1,
        outputs: 1,
        icon: "bridge.png",
        label: function () {
            return this.name || "grant permission";
        },
        labelStyle: function () {
            return this.name ? "node_label_italic" : "";
        },

        oneditprepare: function () {
            $("#node-input-typed-entities").typedInput({ types: ['msg'] });
            $("#node-input-typed-entities").typedInput('value', this.entities);


            $.getJSON('api_roles',function(data) {
                $.each(data, function(i, ele) {
                    $('#node-input-targetid-select').append($('<option>', { 
                        value: ele._id,
                        text : ele.name
                    }));
                });
                $('#node-input-targetid-select').val($('#node-input-targetid').val());
            });

        },
        oneditsave: function () {
            $('#node-input-targetid').val($('#node-input-targetid-select').val());
            $("#node-input-entities").val($("#node-input-typed-entities").typedInput('value'));
        }

    });
</script>







<script type="text/x-red" data-template-name="revoke permission">
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
    <div class="form-row">
        <label for="node-input-targetid"><i class="fa fa-tasks"></i> Target</label>
        <select id="node-input-targetid-select">
        </select>
        <input id="node-input-targetid" type="hidden">
    </div>
    <div class="form-row">
        <label for="node-input-typed-entities"><i class="fa fa-list"></i> Entities</label>
        <input id="node-input-typed-entities" type="text" style="width: 70%">
        <input id="node-input-entities" type="hidden">
    </div>
    <div class="form-row">
        <label><i class="fa fa-tag"></i> Bitsexplained </label>
        (F:-1, R:2, U:3, D:4, I:5)
    </div>
    <div class="form-row">
        <label for="node-input-bits"><i class="fa fa-tag"></i> Bits </label>
        <input type="text" id="node-input-bits" placeholder="Bits seperated by comma,">
    </div>
</script>
<script type="text/x-red" data-help-name="revoke permission">
    <p>Revoke a specific permission for a role (or user if set by msg.targetid) on the entity/entities in payload.</p>
</script>
<script type="text/javascript">
    RED.nodes.registerType('revoke permission', {
        category: 'api',
        color: "#a6bbcf",
        defaults: {
            name: { value: "" },
            targetid: { value: "result._id", required: true },
            entities: { value: "payload", required: true },
            bits: { value: "", required: true }
        },
        inputs: 1,
        outputs: 1,
        icon: "bridge.png",
        label: function () {
            return this.name || "revoke permission";
        },
        labelStyle: function () {
            return this.name ? "node_label_italic" : "";
        },

        oneditprepare: function () {
            $("#node-input-typed-entities").typedInput({ types: ['msg'] });
            $("#node-input-typed-entities").typedInput('value', this.entities);


            $.getJSON('api_roles',function(data) {
                $.each(data, function(i, ele) {
                    $('#node-input-targetid-select').append($('<option>', { 
                        value: ele._id,
                        text : ele.name
                    }));
                });
                $('#node-input-targetid-select').val($('#node-input-targetid').val());
            });

        },
        oneditsave: function () {
            $('#node-input-targetid').val($('#node-input-targetid-select').val());
            $("#node-input-entities").val($("#node-input-typed-entities").typedInput('value'));
        }

    });
</script>













<script type="text/x-red" data-template-name="map reduce">
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="Name">
    </div>
    <div class="form-row" style="margin-bottom: 0px;">
        <label for="node-input-map"><i class="fa fa-wrench"></i> Map</label>
        <input type="hidden" id="node-input-map" autofocus="autofocus">
        <input type="hidden" id="node-input-noerr-map">
    </div>
    <div class="form-row node-text-editor-row" style="position:relative">
        <div style="position: absolute; right:0; bottom:calc(100% + 3px);"><button id="node-function-expand-js-map" class="editor-button editor-button-small"><i class="fa fa-expand"></i></button></div>
        <div style="height: 100px; min-height:100px;" class="node-text-editor" id="node-input-map-editor" ></div>
    </div>
    <div class="form-row" style="margin-bottom: 0px;">
        <label for="node-input-reduce"><i class="fa fa-wrench"></i> Reduce</label>
        <input type="hidden" id="node-input-reduce" autofocus="autofocus">
        <input type="hidden" id="node-input-noerr-reduce">
    </div>
    <div class="form-row node-text-editor-row" style="position:relative">
        <div style="position: absolute; right:0; bottom:calc(100% + 3px);"><button id="node-function-expand-js-reduce" class="editor-button editor-button-small"><i class="fa fa-expand"></i></button></div>
        <div style="height: 100px; min-height:100px;" class="node-text-editor" id="node-input-reduce-editor" ></div>
    </div>
    <div class="form-row" style="margin-bottom: 0px;">
        <label for="node-input-finalize"><i class="fa fa-wrench"></i> finalize</label>
        <input type="hidden" id="node-input-finalize" autofocus="autofocus">
        <input type="hidden" id="node-input-noerr-finalize">
    </div>
    <div class="form-row node-text-editor-row" style="position:relative">
        <div style="position: absolute; right:0; bottom:calc(100% + 3px);"><button id="node-function-expand-js-finalize" class="editor-button editor-button-small"><i class="fa fa-expand"></i></button></div>
        <div style="height: 100px; min-height:100px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
    </div>
    <div class="form-row">
        <label><i class="fa fa-list"></i> Scope </label>
        <input id="node-input-typed-scope" type="text" style="width: 70%">
        <input id="node-input-scope" type="hidden">
    </div>

    <div class="form-row">
        <label for="node-input-output"><i class="fa fa-tag"></i> Output</label>
        <select type="text" id="node-input-output">
            <option>replace</option>
            <option>merge</option>
            <option>reduce</option>
            <option>inline</option>
        </select>
    </div>
    <div class="form-row">
        <label for="node-input-outcol"><i class="fa fa-tag"></i> Out collection</label>
        <input type="text" id="node-input-outcol" placeholder="Output collection">
    </div>
    <div class="form-row">
        <label for="node-input-query"><i class="fa fa-tag"></i> Out collection</label>
        <input type="text" id="node-input-query" placeholder="Output collection">
    </div>

</script>
<script type="text/x-red" data-help-name="map reduce">
    <p>
        Run a mapreduce on a collection.
        If output is set for inline, the result will be returned in payload, for all else, you can get the result in the receiving collection.<br>
        Finalize is optional, and can be left blank if not needed.<br>
        Be carefull to keep _acl on all reduced objects, so you have permission to read the result.<br>
        <a href="https://docs.mongodb.com/manual/tutorial/map-reduce-examples/index.html">map-reduce-examples</a><br>
<a href="https://docs.mongodb.com/manual/reference/method/db.collection.mapReduce/#db.collection.mapReduce">dokumentation</a>
    </p>
</script>
<script type="text/javascript">
    RED.nodes.registerType('map reduce', {
        category: 'api',
        color: "#a6bbcf",
        defaults: {
            name: { value: "" },
            collection: { value: "entities", required: true },
            map: { value: 
`function map(this) {
    emit(this._type, this);
}`, required: true },
            reduce: { value: 
`function reduce(key, values) {
    var reducedObject = { count: 0, value: 0, avg: 0, _acl: [] };
    values.forEach(function (value) {
        reducedObject.value += value.value;
        reducedObject.count += value.count;
        reducedObject._acl = value._acl;
    });
    return reducedObject;
}`, required: true },
            finalize: { value: 
`function finalize(key, reducedValue) {
    if (reducedValue.count > 0) {
        reducedValue.avg = reducedValue.value / reducedValue.count;
    }
    return reducedValue;
}` },
            scope: { value: "payload.scope", required: false },
            output: { value: "inline", required: true },
            outcol: { value: "1", required: true },
            query: { value: "{}", required: true },

            noerr: {value:0,required:true,validate:function(v) { return ((!v) || (v === 0)) ? true : false; }}
        },
        inputs: 1,
        outputs: 1,
        icon: "bridge.png",
        label: function () {
            return this.name || "map reduce";
        },
        labelStyle: function () {
            return this.name ? "node_label_italic" : "";
        },

        oneditprepare: function () {
            this.mapeditor = RED.editor.createEditor({
                id: 'node-input-map-editor',
                mode: 'ace/mode/nrjavascript',
                value: $("#node-input-map").val(),
                globals: {
                    msg: false,
                    context: false,
                    RED: false,
                    util: true,
                    flow: false,
                    global: false,
                    console: false,
                    Buffer: true,
                    setTimeout: false,
                    clearTimeout: false,
                    setInterval: false,
                    clearInterval: false
                }
            });
            this.mapeditor.focus();

            this.reduceeditor = RED.editor.createEditor({
                id: 'node-input-reduce-editor',
                mode: 'ace/mode/nrjavascript',
                value: $("#node-input-reduce").val(),
                globals: {
                    msg: false,
                    context: false,
                    RED: false,
                    util: true,
                    flow: false,
                    global: false,
                    console: false,
                    Buffer: true,
                    setTimeout: false,
                    clearTimeout: false,
                    setInterval: false,
                    clearInterval: false
                }
            });

            this.finalizeeditor = RED.editor.createEditor({
                id: 'node-input-finalize-editor',
                mode: 'ace/mode/nrjavascript',
                value: $("#node-input-finalize").val(),
                globals: {
                    msg: false,
                    context: false,
                    RED: false,
                    util: true,
                    flow: false,
                    global: false,
                    console: false,
                    Buffer: true,
                    setTimeout: false,
                    clearTimeout: false,
                    setInterval: false,
                    clearInterval: false
                }
            });

            var that = this;
            $("#node-function-expand-js-map").click(function(e) {
                e.preventDefault();
                var value = that.mapeditor.getValue();
                RED.editor.editJavaScript({
                    value: value,
                    width: "Infinity",
                    cursor: that.mapeditor.getCursorPosition(),
                    mode: "ace/mode/nrjavascript",
                    complete: function(v,cursor) {
                        that.mapeditor.setValue(v, -1);
                        that.mapeditor.gotoLine(cursor.row+1,cursor.column,false);
                        setTimeout(function() {
                            that.mapeditor.focus();
                        },300);
                    }
                })
            });
            $("#node-function-expand-js-reduce").click(function(e) {
                e.preventDefault();
                var value = that.reduceeditor.getValue();
                RED.editor.editJavaScript({
                    value: value,
                    width: "Infinity",
                    cursor: that.reduceeditor.getCursorPosition(),
                    mode: "ace/mode/nrjavascript",
                    complete: function(v,cursor) {
                        that.reduceeditor.setValue(v, -1);
                        that.reduceeditor.gotoLine(cursor.row+1,cursor.column,false);
                        setTimeout(function() {
                            that.reduceeditor.focus();
                        },300);
                    }
                })
            });
            $("#node-function-expand-js-finalize").click(function(e) {
                e.preventDefault();
                var value = that.finalizeeditor.getValue();
                RED.editor.editJavaScript({
                    value: value,
                    width: "Infinity",
                    cursor: that.finalizeeditor.getCursorPosition(),
                    mode: "ace/mode/nrjavascript",
                    complete: function(v,cursor) {
                        that.finalizeeditor.setValue(v, -1);
                        that.finalizeeditor.gotoLine(cursor.row+1,cursor.column,false);
                        setTimeout(function() {
                            that.finalizeeditor.focus();
                        },300);
                    }
                })
            });


            $("#node-input-typed-scope").typedInput(
                { types: ['msg'] }
            );
            $("#node-input-typed-scope").typedInput('value', this.scope);

        },
        oneditsave: function () {
            this.noerr = 0;

            var annot = this.mapeditor.getSession().getAnnotations();
            $("#node-input-noerr-map").val(0);
            for (var k=0; k < annot.length; k++) {
                console.log(annot[k].type,":",annot[k].text, "on line", annot[k].row);
                if (annot[k].type === "error") {
                    $("#node-input-noerr-map").val(annot.length);
                    this.noerr = annot.length;
                }
            }

            annot = this.reduceeditor.getSession().getAnnotations();
            $("#node-input-noerr-reduce").val(0);
            for (var k=0; k < annot.length; k++) {
                console.log(annot[k].type,":",annot[k].text, "on line", annot[k].row);
                if (annot[k].type === "error") {
                    $("#node-input-noerr-reduce").val(annot.length);
                    this.noerr = annot.length;
                }
            }

            annot = this.finalizeeditor.getSession().getAnnotations();
            $("#node-input-noerr-finalize").val(0);
            for (var k=0; k < annot.length; k++) {
                console.log(annot[k].type,":",annot[k].text, "on line", annot[k].row);
                if (annot[k].type === "error") {
                    $("#node-input-noerr-finalize").val(annot.length);
                    this.noerr = annot.length;
                }
            }

            $("#node-input-map").val(this.mapeditor.getValue());
            this.mapeditor.destroy();
            delete this.mapeditor;

            $("#node-input-reduce").val(this.reduceeditor.getValue());
            this.reduceeditor.destroy();
            delete this.reduceeditor;

            $("#node-input-finalize").val(this.finalizeeditor.getValue());
            this.finalizeeditor.destroy();
            delete this.finalizeeditor;

            $("#node-input-scope").val($("#node-input-typed-scope").typedInput('value'));

        },
        oneditcancel: function() {
            this.mapeditor.destroy();
            delete this.mapeditor;

            this.reduceeditor.destroy();
            delete this.reduceeditor;

            this.finalizeeditor.destroy();
            delete this.finalizeeditor;
        },
        oneditresize: function(size) {
            // var rows = $("#dialog-form>div:not(.node-text-editor-row)");
            // var height = $("#dialog-form").height();
            // for (var i=0; i<rows.size(); i++) {
            //     height -= $(rows[i]).outerHeight(true);
            // }
            // var editorRow = $("#dialog-form>div.node-text-editor-row");
            // height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
            // $(".node-text-editor").css("height",height+"px");
            // this.editor.resize();
            // this.reduceeditor.resize();
            // this.finalizeeditor.resize();
        }

    });
</script>
